package com.easylinkin.linkappapi.openapi.util;

import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.easylinkin.bases.redis.util.RedisUtil;
import com.easylinkin.linkappapi.facerecognition.util.SpringContextUtil;
import com.easylinkin.linkappapi.openapi.dto.systemDock.DockParticipatingUnitsDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;

import java.io.*;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class HttpClientUtil {

	/** 一分钟内请求超时circuitBreakerNum次，进行熔断，时间5分钟 */
	public static final TimedCache<String, AtomicInteger> circuitBreakerCount =
			CacheUtil.newTimedCache(TimeUnit.MINUTES.toMillis(5));
	/** 一分钟内请求超时几次 */
	public static final int circuitBreakerNum = 5;

	public static String doPost(HttpPost httpPost) {
		CloseableHttpClient httpClient = null;
		String result = null;
		try {
			httpClient = HttpClientBuilder.create().build();
			HttpResponse response = httpClient.execute(httpPost);
			if (response != null) {
				HttpEntity resEntity = response.getEntity();
				if (resEntity != null) {
					result = EntityUtils.toString(resEntity, "utf-8");
				}
			}
		} catch (Exception ex) {
			log.error(ex.getMessage(), ex);
		}
		return result;
	}

	public static String doPut(HttpPut httpPost) {
	  CloseableHttpClient httpClient = null;
	  String result = null;
	  try {
	    httpClient = HttpClientBuilder.create().build();
	    HttpResponse response = httpClient.execute(httpPost);
	    if (response != null) {
	      HttpEntity resEntity = response.getEntity();
	      if (resEntity != null) {
	        result = EntityUtils.toString(resEntity, "utf-8");
	      }
	    }
	  } catch (Exception ex) {
	    log.error(ex.getMessage(), ex);
	  }
	  return result;
	}

	public static String doDelete(HttpDelete httpPost) {
	  CloseableHttpClient httpClient = null;
	  String result = null;
	  try {
	    httpClient = HttpClientBuilder.create().build();
	    HttpResponse response = httpClient.execute(httpPost);
	    if (response != null) {
	      HttpEntity resEntity = response.getEntity();
	      if (resEntity != null) {
	        result = EntityUtils.toString(resEntity, "utf-8");
	      }
	    }
	  } catch (Exception ex) {
	    log.error(ex.getMessage(), ex);
	  }
	  return result;
	}

	public static String doGet(HttpGet httpGet) {
		CloseableHttpClient httpClient = null;
		String result = null;
		try {
			httpClient = HttpClientBuilder.create().build();
			HttpResponse response = httpClient.execute(httpGet);
			if (response != null) {
				HttpEntity resEntity = response.getEntity();
				if (resEntity != null) {
					result = EntityUtils.toString(resEntity, "utf-8");
				}
			}
		} catch (Exception ex) {
			log.error(ex.getMessage(), ex);
		}
		return result;
	}

	/**
	 * 参数转换为url拼接形式	结果示例:sex=男&name=lqh&address=武汉
	 * @author liuqihang
	 * @param source
	 * @return
	 */
	public static String asUrlParams(Map<String, Object> source){
		Iterator<String> it = source.keySet().iterator();
		StringBuilder paramStr = new StringBuilder();
		while (it.hasNext()){
			String key = it.next();
			Object value = source.get(key);
			if (value == null){
				continue;
			}
			String valueStr = null;
			try {
				valueStr = URLEncoder.encode(value.toString(), "UTF-8");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			paramStr.append("&").append(key).append("=").append(valueStr);
		}
		return paramStr.substring(1);
	}

	public static void main(String[] args) throws IOException {

//		while (true){
//			try {
//				doPost("http://119.96.216.22:9050", "{\"aa\":\"123\"}");
//			}catch (Exception e){
//				e.printStackTrace();
//			}
//		}
		DockParticipatingUnitsDTO dockParticipatingUnitsDTO = new DockParticipatingUnitsDTO();
		dockParticipatingUnitsDTO.setUnittype("001");
		dockParticipatingUnitsDTO.setAreaCode("test");
		dockParticipatingUnitsDTO.setBuilderLicenses("test");
		dockParticipatingUnitsDTO.setCreditunits("914302001842901362");
		dockParticipatingUnitsDTO.setName("test1");
		String infostr = dockParticipatingUnitsDTO.toString();
		String info = JSON.toJSONString(dockParticipatingUnitsDTO);
		System.out.println(info);
		doPost("http://2.huhu520.com:50098/api_v1/modules/issueinfo/unitAdd", info);
//		JSONObject jsonObject = JSONObject.parseObject(str);
//		System.out.println(jsonObject.get("data"));
		String str1 = doGet(new HttpGet("http://2.huhu520.com:50098/api_v1/modules/teams/getUnitInfo?projUid=110110255"));
		JSONObject jsonObject = JSONObject.parseObject(str1);
		JSONArray unitList = jsonObject.getJSONArray("data");
		List<DockParticipatingUnitsDTO> units = unitList.toJavaList(DockParticipatingUnitsDTO.class);
		System.out.println(units.toString());
	}

	/**
	 * post请求
	 *
	 * @param path url地址
	 * @param Info jsonobject 参数
	 * @return
	 * @throws IOException
	 */
	public static String doPost(String path, String Info) throws IOException {

		if (circuitBreakerCount.containsKey(path)
				&& circuitBreakerCount.get(path, false).get() >= circuitBreakerNum) {
			String format = String.format("发送失败-熔断器开启中url:%s", path);
			throw new RuntimeException(format);
		}
		RequestConfig requestConfig = RequestConfig.custom()
				.setSocketTimeout(5000)
				.setConnectTimeout(5000)
				.setConnectionRequestTimeout(3000)
				.build();
		HttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
		HttpPost post = new HttpPost(path);

		post.setHeader("Content-Type", "application/json");
		post.addHeader("Authorization", "Basic YWRtaW46");
		String result = "";

		try {
			StringEntity s = new StringEntity(Info, "utf-8");
			s.setContentEncoding("application/json");
			post.setEntity(s);

			// 发送请求
			HttpResponse httpResponse = client.execute(post);

			// 获取响应输入流
			InputStream inStream = httpResponse.getEntity().getContent();
			BufferedReader reader = new BufferedReader(new InputStreamReader(inStream, "utf-8"));
			StringBuilder strber = new StringBuilder();
			String line = null;
			while ((line = reader.readLine()) != null)
				strber.append(line + "\n");
			inStream.close();

			result = strber.toString();
			System.out.println(result);
			if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				System.out.println("请求服务器成功，做相应处理");
			} else {
				System.out.println("请求服务端失败");
			}

		} catch (Exception e) {
			Throwable cause = e.getCause();
			boolean isConnect = (e instanceof ConnectException || (cause instanceof ConnectException)) ||
					(e instanceof SocketTimeoutException || (cause instanceof SocketTimeoutException));
			if (isConnect) {
				result = "发送失败-请求超时";
				boolean init = false;
				if (!circuitBreakerCount.containsKey(path)) {
					synchronized (circuitBreakerCount) {
						if (!circuitBreakerCount.containsKey(path)) {
							// 一分钟内的错误
							circuitBreakerCount.put(path, new AtomicInteger(1), TimeUnit.SECONDS.toMillis(60));
							init = true;
						}
					}
				}
				if (!init) {
					AtomicInteger count = circuitBreakerCount.get(path, false);
					int addAndGet = count.addAndGet(1);
					if (addAndGet == circuitBreakerNum) {
						log.warn("推送熔断器启用url:{} 原因: {}", path, e.getMessage());
						result = String.format("%s 熔断器开启", result);
						// 熔断5分钟
						circuitBreakerCount.put(path, count, TimeUnit.MINUTES.toMillis(5));
						SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
						SimpleDateFormat sdf2 = new SimpleDateFormat("yyyyMMdd");
						RedisUtil redisUtil = SpringContextUtil.getBean(RedisUtil.class);
						redisUtil.lSet("circuitBreaker:"+sdf2.format(new Date()), String.format("%s-%s", path, sdf.format(new Date())));
						redisUtil.expire("circuitBreaker:"+sdf2.format(new Date()), 3*24*60*60);
					}
				}
			}
			throw new RuntimeException(e);
		}

		return result;
	}


	/**
	 * post请求
	 *
	 * @param path url地址
	 * @param Info jsonobject 参数
	 * @return
	 * @throws IOException
	 */
	public static String doPostToken(String path, String Info,String token) {

		HttpClient client = HttpClientBuilder.create().build();
		HttpPost post = new HttpPost(path);

		post.setHeader("Content-Type", "application/json");
		post.addHeader("Authorization", "bearer "+token);
		String result = "";

		try {
			StringEntity s = new StringEntity(Info, "utf-8");
			s.setContentEncoding("application/json");
			post.setEntity(s);

			// 发送请求
			HttpResponse httpResponse = client.execute(post);

			// 获取响应输入流
			InputStream inStream = httpResponse.getEntity().getContent();
			BufferedReader reader = new BufferedReader(new InputStreamReader(inStream, "utf-8"));
			StringBuilder strber = new StringBuilder();
			String line = null;
			while ((line = reader.readLine()) != null)
				strber.append(line + "\n");
			inStream.close();

			result = strber.toString();
			System.out.println(result);
			if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				System.out.println("请求服务器成功，做相应处理");
			} else {
				System.out.println("请求服务端失败");
			}

		} catch (Exception e) {
			System.out.println("请求异常");
			throw new RuntimeException(e);
		}

		return result;
	}

	/**
	 * post请求
	 *
	 * @param path url地址
	 * @param Info jsonobject 参数
	 * @return
	 * @throws IOException
	 */
	public static String doPostApply(String path, String Info, String applyId) throws IOException {

		if (circuitBreakerCount.containsKey(path)
				&& circuitBreakerCount.get(path, false).get() >= circuitBreakerNum) {
			String format = String.format("发送失败-熔断器开启中url:%s", path);
			throw new RuntimeException(format);
		}
		RequestConfig requestConfig = RequestConfig.custom()
				.setSocketTimeout(5000)
				.setConnectTimeout(5000)
				.setConnectionRequestTimeout(3000)
				.build();
		HttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
		HttpPost post = new HttpPost(path);

		post.setHeader("Content-Type", "application/json");
		post.addHeader("applyId", applyId);
		String result = "";

		try {
			StringEntity s = new StringEntity(Info, "utf-8");
			s.setContentEncoding("application/json");
			post.setEntity(s);

			// 发送请求
			HttpResponse httpResponse = client.execute(post);

			// 获取响应输入流
			InputStream inStream = httpResponse.getEntity().getContent();
			BufferedReader reader = new BufferedReader(new InputStreamReader(inStream, "utf-8"));
			StringBuilder strber = new StringBuilder();
			String line = null;
			while ((line = reader.readLine()) != null)
				strber.append(line + "\n");
			inStream.close();

			result = strber.toString();
			System.out.println(result);
			if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				System.out.println("请求服务器成功，做相应处理");
			} else {
				System.out.println("请求服务端失败");
			}

		} catch (Exception e) {
			Throwable cause = e.getCause();
			boolean isConnect = (e instanceof ConnectException || (cause instanceof ConnectException)) ||
					(e instanceof SocketTimeoutException || (cause instanceof SocketTimeoutException));
			if (isConnect) {
				result = "发送失败-请求超时";
				boolean init = false;
				if (!circuitBreakerCount.containsKey(path)) {
					synchronized (circuitBreakerCount) {
						if (!circuitBreakerCount.containsKey(path)) {
							// 一分钟内的错误
							circuitBreakerCount.put(path, new AtomicInteger(1), TimeUnit.SECONDS.toMillis(60));
							init = true;
						}
					}
				}
				if (!init) {
					AtomicInteger count = circuitBreakerCount.get(path, false);
					int addAndGet = count.addAndGet(1);
					if (addAndGet == circuitBreakerNum) {
						log.warn("推送熔断器启用url:{} 原因: {}", path, e.getMessage());
						result = String.format("%s 熔断器开启", result);
						// 熔断5分钟
						circuitBreakerCount.put(path, count, TimeUnit.MINUTES.toMillis(5));
						SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
						SimpleDateFormat sdf2 = new SimpleDateFormat("yyyyMMdd");
						RedisUtil redisUtil = SpringContextUtil.getBean(RedisUtil.class);
						redisUtil.lSet("circuitBreaker:"+sdf2.format(new Date()), String.format("%s-%s", path, sdf.format(new Date())));
						redisUtil.expire("circuitBreaker:"+sdf2.format(new Date()), 3*24*60*60);
					}
				}
			}
			throw new RuntimeException(e);
		}

		return result;
	}
}
